package com.bird.system.service.impl;

import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.net.URLEncoder;
import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.alibaba.fastjson.parser.Feature;
import com.bird.common.constant.Constants;
import com.bird.common.exception.CustomException;
import com.bird.common.utils.HttpRequest;
import com.bird.common.utils.HttpResponse;
import com.bird.common.utils.HttpUtil;
import com.bird.common.utils.StringUtil;
import com.bird.common.utils.covert.ConfigIdCovert;
import com.bird.common.utils.function.FunctionExecutor;
import com.bird.common.utils.tkmybatis.TK;
import com.bird.system.domain.bo.Address;
import com.bird.system.domain.entity.TsGroupApiConfigEntity;
import com.bird.system.domain.entity.TsGroupApiEntity;
import com.bird.system.domain.entity.TsPhoneDataEntity;
import com.bird.system.domain.entity.TsReqLogEntity;
import com.bird.system.domain.params.TsGroupApiConfigQueryParam;
import com.bird.system.domain.params.TsGroupApiConfigUpdateParam;
import com.bird.system.domain.vo.TsGroupApiConfigInfoPcVo;
import com.bird.system.domain.vo.TsGroupApiConfigListPcVO;
import com.bird.system.enums.BaseEnum;
import com.bird.system.enums.FlagEnum;
import com.bird.system.enums.MatchTypeEnum;
import com.bird.system.enums.ProxyHostEnum;
import com.bird.system.enums.ReqContentTypeEnum;
import com.bird.system.enums.ReqHttpMethodEnum;
import com.bird.system.enums.ReqStatusEnum;
import com.bird.system.enums.RspResultEnum;
import com.bird.system.enums.SysYesOrNoEnum;
import com.bird.system.mapper.TsGroupApiConfigMapper;
import com.bird.system.service.ISysCodeRuleService;
import com.bird.system.service.ISysDictDataService;
import com.bird.system.service.ITsGroupApiConfigService;
import com.bird.system.service.ITsGroupApiService;
import com.bird.system.service.ITsPhoneDataService;
import com.bird.system.service.TaskStatusManageService;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 请求任务配置Service业务层处理
 *
 * @author bird
 * @date 2020-09-23
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class TsGroupApiConfigServiceImpl extends IBaseServiceImpl<TsGroupApiConfigEntity, TsGroupApiConfigMapper> implements ITsGroupApiConfigService {

	@Autowired
	private List<FunctionExecutor> functionExecutors;

	@Autowired
	private ITsGroupApiService tsGroupApiService;

	@Autowired
	private ITsPhoneDataService tsPhoneDataService;

	@Autowired
	private TaskStatusManageService taskStatusManageService;

	@Autowired
	private ISysCodeRuleService sysCodeRuleService;

	@Autowired
	private ISysDictDataService sysDictDataService;


	/**
	 * 控制执行器
	 */
	private static final Map<Long, ExecutorService> executors = new ConcurrentHashMap<>();

	/**
	 * 控制执行器
	 */
	private static final Map<Long, Thread> theaders = new ConcurrentHashMap<>();

	/**
	 * 查询请求任务配置列表
	 *
	 * @param queryParam 请求任务配置 查询参数
	 * @return 请求任务配置
	 */
	@Override
	public List<TsGroupApiConfigListPcVO> selectListPC(TsGroupApiConfigQueryParam queryParam) {
		List<TsGroupApiConfigListPcVO> tsGroupApiConfigs = mapper.selectListPC(queryParam);
		return tsGroupApiConfigs;
	}

	/**
	 * 新增请求任务配置
	 *
	 * @param updateParam 请求任务配置 新增参数
	 * @return 结果
	 */
	@Override
	public Long insertPC(TsGroupApiConfigUpdateParam updateParam, Long userId) {
		TsGroupApiConfigEntity entity = updateParam.covert();
		// 如果是jsonpath,检查填写是否正确
		if (entity.getMatchType().equals(MatchTypeEnum.JSON_PATH.getKey())) {
			if (!entity.getMatchPattern().contains(":")) {
				throw new CustomException("jsonpath 匹配模式格式为: path:value");
			}
		}
		// 检测是否自定义数据
		boolean custom = checkCustom(entity.getReqDataId());
		entity.setCreSb(userId);
		// 结果保存表达式验证
		String jsonVal = tsGroupApiService.keyValueDataCovertJson(entity.getStoreVar());
		if (StringUtil.isNotBlank(jsonVal)) {
			JSONObject json = JSONObject.parseObject(jsonVal, Feature.OrderedField);
			Set<String> keys = json.keySet();
			for (String key : keys) {
				String val = json.getString(key);
				checkJsonPath(val);
			}
			entity.setStoreVar(jsonVal);
		}
		// 如果是jsonpath匹配，校验path
		if (entity.getMatchType().equals(MatchTypeEnum.JSON_PATH.getKey())) {
			checkJsonPath(entity.getMatchPattern());
		}
		entity.setExtraVar(tsGroupApiService.keyValueDataCovertJson(entity.getExtraVar()));
		// 根据分页大小，计算总页数
		long totalPage = 1L;
		if (custom) {
			totalPage = totalPageCustom(entity.getPageSize(), entity.getReqDataId());
		} else {
			totalPage = totalPage(entity.getPageSize(), entity.getReqDataId(), userId);
		}
		entity.setPageTotal(totalPage);
		entity.setPageNum(1L);
		this.insert(entity);
		ConfigIdCovert.existUser.remove(entity.getId());
		return entity.getId();
	}

	/**
	 * 检查自定义模拟规则是否正确
	 *
	 * @param reqDataId
	 */
	private boolean checkCustom(String reqDataId) {
		if (reqDataId.contains("custom")) {
			// 只有一个，不等于这个，则表示规则错误
			if (!reqDataId.matches("custom:num:\\d+:\\d+:\\d+")) {
				throw new CustomException("自定义规则错误，如 custom:num:1:10000:2");
			}
			return true;
		}
		return false;
	}

	/**
	 * 检查JsonPath是否填写正确
	 *
	 * @param path
	 */
	private void checkJsonPath(String path) {
		try {
			JSONPath.eval(new JSONObject(), path);
		} catch (Exception e) {
			throw new CustomException("JsonPath语法不正确!");
		}

	}

	/**
	 * 根据请求的数据计算分页大小
	 *
	 * @param pageSize
	 * @param reqDataStr
	 * @return
	 */
	private long totalPage(long pageSize, String reqDataStr, Long creSb) {
		long totalSize = tsPhoneDataService.countByParams(
				TK.select(TsPhoneDataEntity.class).where()
						.andIn(TsPhoneDataEntity::getTheName, reqDataStr.split(","))
						.andEqualTo(TsPhoneDataEntity::getCreSb, creSb)
						.end()
		);
		return (totalSize - 1) / pageSize + 1;
	}

	/**
	 * 根据请求的数据计算分页大小,自定义数据
	 *
	 * @param pageSize
	 * @param reqDataRule
	 * @return
	 */
	private long totalPageCustom(long pageSize, String reqDataRule) {
		long totalSize = 0;
		// 自定义数据, 前缀:类型:开始:结束:步长
		String[] cusomtRule = reqDataRule.split(":");
		// 2 10 2
		long start = Long.parseLong(cusomtRule[2]);
		long end = Long.parseLong(cusomtRule[3]);
		long size = Long.parseLong(cusomtRule[4]);
		totalSize = (end - start) / size + 1;
		return (totalSize - 1) / pageSize + 1;
	}

	/**
	 * 修改请求任务配置
	 *
	 * @param updateParam 请求任务配置 修改参数
	 * @return 结果
	 */
	@Override
	public int updateByIdPC(TsGroupApiConfigUpdateParam updateParam, Long userId) {
		TsGroupApiConfigEntity entity = updateParam.covert();
		// 如果是jsonpath,检查填写是否正确
		if (entity.getMatchType().equals(MatchTypeEnum.JSON_PATH.getKey())) {
			if (!entity.getMatchPattern().contains(":")) {
				throw new CustomException("jsonpath 匹配模式格式为: path:value");
			}
		}
		// 检测是否自定义数据
		boolean custom = checkCustom(entity.getReqDataId());
		// 结果保存表达式验证
		String jsonVal = tsGroupApiService.keyValueDataCovertJson(entity.getStoreVar());
		if (StringUtil.isNotBlank(jsonVal)) {
			JSONObject json = JSONObject.parseObject(jsonVal, Feature.OrderedField);
			Set<String> keys = json.keySet();
			for (String key : keys) {
				String val = json.getString(key);
				checkJsonPath(val);

			}
			entity.setStoreVar(jsonVal);
		}
		// 如果是jsonpath匹配，校验path
		if (entity.getMatchType().equals(MatchTypeEnum.JSON_PATH.getKey())) {
			checkJsonPath(entity.getMatchPattern());
		}
		entity.setExtraVar(tsGroupApiService.keyValueDataCovertJson(entity.getExtraVar()));
		// 根据分页大小，计算总页数
		long totalPage = 1L;
		if (custom) {
			totalPage = totalPageCustom(entity.getPageSize(), entity.getReqDataId());
		} else {
			totalPage = totalPage(entity.getPageSize(), entity.getReqDataId(), userId);
		}
		entity.setPageTotal(totalPage);
		entity.setPageNum(1L);
		int result = this.updateById(entity);

		ConfigIdCovert.existUser.remove(entity.getId());
		return result;
	}

	@Override
	public TsGroupApiConfigInfoPcVo selectByIdPc(Long id) {
		TsGroupApiConfigInfoPcVo tsGroupApiConfigInfoPcVo = mapper.selectByIdPc(id);
		tsGroupApiConfigInfoPcVo.setStoreVar(tsGroupApiService.jsonDataCovertKeyValue(tsGroupApiConfigInfoPcVo.getStoreVar()));
		tsGroupApiConfigInfoPcVo.setExtraVar(tsGroupApiService.jsonDataCovertKeyValue(tsGroupApiConfigInfoPcVo.getExtraVar()));
		return tsGroupApiConfigInfoPcVo;
	}

	/**
	 * 检测代理
	 */
	private void checkProxy(Address proxyHost) {
		try {
			String result = HttpUtil.get("http://" + proxyHost.getHost() + ":" + proxyHost.getPort()).proxyBasic(proxyHost.getUsername(), proxyHost.getPassword()).execute();
		} catch (Exception e) {
			e.printStackTrace();
			throw new CustomException("代理异常:" + proxyHost.toString());
		}
	}

	public static void main(String[] args) throws IOException {
		HttpRequest httpRequest = HttpRequest.create().url("https://www.baidu.com");
		httpRequest.proxy("tps113.kdlapi.com", 15818);
		httpRequest.proxyBasic("t10137352511050", "x0nd7pn9");
		HttpResponse execute = httpRequest.execute();
		System.out.println(execute.getHtml());
	}

	@Override
	public void start(Long id) {
		// 开始锁
		try {
			taskStatusManageService.lock(id);
			// 查询任务配置
			TsGroupApiConfigEntity tsGroupApiConfigEntity = this.selectById(id);
			// 查询接口信息
			TsGroupApiEntity tsGroupApiEntity = tsGroupApiService.selectById(tsGroupApiConfigEntity.getApiId());
			// 最后一次请求标志
			String lastReqId = "Z" + tsGroupApiEntity.getGroupId() + "-J" + tsGroupApiConfigEntity.getApiId() + "-P" + id + "-" + sysCodeRuleService.buildCode(Constants.GenCode.REQ_MARK);
			// 魔法变量，json字符串
			String extraVar = tsGroupApiConfigEntity.getExtraVar();
			JSONObject extraVarObject = null;
			if (StringUtil.isNotBlank(extraVar)) {
				extraVarObject = JSONObject.parseObject(extraVar, Feature.OrderedField);
			}
			// 网络请求地址
			String theUrl = tsGroupApiEntity.getTheUrl();
			// url参数
			String urlParam = handleUrlParams(tsGroupApiEntity.getUrlParam(), extraVarObject);
			// body内容，json字符串
			String bodyParam = handleBody(tsGroupApiEntity.getBodyParam(), extraVarObject);
			// header参数，json字符串
			String headerParam = handleHeader(tsGroupApiEntity.getHeaderParam(), extraVarObject);
			// 请求协议类型
			ReqContentTypeEnum contentType = (ReqContentTypeEnum) BaseEnum.valueOfEnum(ReqContentTypeEnum.class, tsGroupApiEntity.getContentType());
			// 请求方式
			ReqHttpMethodEnum methodType = (ReqHttpMethodEnum) BaseEnum.valueOfEnum(ReqHttpMethodEnum.class, tsGroupApiEntity.getTheMethod());

			// 更改任务状态
			tsGroupApiConfigEntity.setPageNum(1L);
			tsGroupApiConfigEntity.setStartNum(1L + tsGroupApiConfigEntity.getStartNum());
			tsGroupApiConfigEntity.setReqStatus(ReqStatusEnum.REQUESTING.getKey());
			this.updateById(tsGroupApiConfigEntity);

			// 代理检查
			String proxyHostSource = tsGroupApiConfigEntity.getProxyHost();
			Address proxy = null;
			if (!Constants.TS.PROXY_NONE.equals(proxyHostSource)) {
				String proxyHost = sysDictDataService.selectDictLabel(ProxyHostEnum.class.getSimpleName(), proxyHostSource);
				proxy = new Address(proxyHost);
				checkProxy(proxy);
			}
			// 异步请求
			ansyExcute(tsGroupApiConfigEntity, methodType, contentType, proxy, theUrl, urlParam, headerParam, bodyParam, lastReqId);
			// 请求ID设置
			TsGroupApiConfigEntity taskUpdate = new TsGroupApiConfigEntity();
			taskUpdate.setId(tsGroupApiConfigEntity.getId());
			taskUpdate.setLastReqId(lastReqId);
			this.updateById(taskUpdate);
		} finally {
			taskStatusManageService.unlock(id);
		}
	}

	private void ansyExcute(TsGroupApiConfigEntity tsGroupApiConfigEntity, ReqHttpMethodEnum methodType, ReqContentTypeEnum contentType, Address proxy, String theUrl, String urlParam, String headerParam, String bodyParam, String lastReqId) {
		// 异步最后
		Thread thread = new Thread(() -> {
			Long taskId = tsGroupApiConfigEntity.getId();
			// 创建任务线程池
			ExecutorService executor = ExecutorBuilder.create()
					.setCorePoolSize(tsGroupApiConfigEntity.getThreadNum())
					.setMaxPoolSize(tsGroupApiConfigEntity.getThreadNum())
					.setWorkQueue(new LinkedBlockingQueue<>())
					.setKeepAliveTime(0)
					.build();
			executors.put(taskId, executor);

			AtomicInteger pageNumSafe = new AtomicInteger(tsGroupApiConfigEntity.getPageNum().intValue());
			while (pageNumSafe.get() <= tsGroupApiConfigEntity.getPageTotal()) {
				// 是否要暂停
				taskStatusManageService.pause(taskId);
				log.info("{} 任务进度{}/{}", taskId, pageNumSafe.get(), tsGroupApiConfigEntity.getPageTotal());
				List<CompletableFuture<TsReqLogEntity>> futureList = new ArrayList<>();
				// 开始拿数据测试
				String[] reqDataArray = tsGroupApiConfigEntity.getReqDataId().split(",");
				if (reqDataArray.length == 1 && reqDataArray[0].contains(Constants.TS.custom)) {
					// 自定义数据, 前缀:类型:开始:结束:步长
					String[] cusomtRule = reqDataArray[0].split(":");
					int pageNum = pageNumSafe.getAndIncrement();
					long size = Long.parseLong(cusomtRule[4]);
					long start = Long.parseLong(cusomtRule[2]) + (pageNum - 1) * size * tsGroupApiConfigEntity.getPageSize().longValue();
					long end = tsGroupApiConfigEntity.getPageSize().longValue() * size * pageNum + Long.parseLong(cusomtRule[2]);
					for (long i = start; i < end; i += size) {
						String phone = String.valueOf(i);
						String finalGroupName = reqDataArray[0];
						CompletableFuture<TsReqLogEntity> future = CompletableFuture.supplyAsync(() -> {
							return excuteUrl(tsGroupApiConfigEntity, methodType, contentType, proxy, theUrl, urlParam, headerParam, bodyParam, phone, finalGroupName);
						}, executor);
						futureList.add(future);
					}
				} else {
					// 真实数据模拟
					PageHelper.startPage(pageNumSafe.getAndIncrement(), tsGroupApiConfigEntity.getPageSize().intValue());
					List<TsPhoneDataEntity> phones = tsPhoneDataService.selectList(
							TK.select(TsPhoneDataEntity.class).column("id", "phone", "theName").where()
									.andIn(TsPhoneDataEntity::getTheName, reqDataArray)
									.andEqualTo(TsPhoneDataEntity::getCreSb, tsGroupApiConfigEntity.getCreSb())
									.end()
					);
					PageHelper.clearPage();
					for (TsPhoneDataEntity data : phones) {
						String phone = data.getPhone();
						String finalGroupName = data.getTheName();
						CompletableFuture<TsReqLogEntity> future = CompletableFuture.supplyAsync(() -> {
							return excuteUrl(tsGroupApiConfigEntity, methodType, contentType, proxy, theUrl, urlParam, headerParam, bodyParam, phone, finalGroupName);
						}, executor);
						futureList.add(future);
					}
				}
				// 阻塞完成任务, 处理结果
				handleExcuteResult(futureList, lastReqId);

				// 进度更新
				TsGroupApiConfigEntity taskUpdate = new TsGroupApiConfigEntity();
				taskUpdate.setId(taskId);
				taskUpdate.setFinishNum(1L + tsGroupApiConfigEntity.getFinishNum());
				taskUpdate.setPageNum((long) pageNumSafe.get() - 1);
				if (taskUpdate.getPageNum() >= tsGroupApiConfigEntity.getPageTotal()) {
					taskUpdate.setReqStatus(ReqStatusEnum.EDN.getKey());
				}
				this.updateById(taskUpdate);
			}

			// 清空资源
			taskStatusManageService.removeAll(taskId);
			executor.shutdown();
			executor = null;
			executors.remove(taskId);
			theaders.remove(taskId);
		});
		thread.start();
		theaders.put(tsGroupApiConfigEntity.getId(), thread);
	}

	/**
	 * 处理结果
	 *
	 * @param results
	 */
	private void handleExcuteResult(List<CompletableFuture<TsReqLogEntity>> results, String lastReqId) {
		try {
			List<TsReqLogEntity> insertList = new ArrayList<>();
			for (CompletableFuture<TsReqLogEntity> result : results) {
				TsReqLogEntity tsReqLogEntity = result.get();
				if (tsReqLogEntity != null) {
					tsReqLogEntity.setLastReqId(lastReqId);
					insertList.add(tsReqLogEntity);
				}
			}
			// 批量插入加速
			if (insertList.isEmpty()) {
				log.info("无需要保存的数据！");
				return;
			}
			this.mapper.insertBatch(insertList);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理Url
	 *
	 * @param urlParams
	 * @param extraVar  魔法变量
	 * @return
	 */
	private String handleUrlParams(String urlParams, JSONObject extraVar) {
		if (extraVar == null || StringUtil.isBlank(urlParams)) {
			return urlParams;
		}
		String sourceUrlParams = URLDecoder.decode(urlParams, Charset.defaultCharset());
		Set<String> keys = extraVar.keySet();
		for (String key : keys) {
			String var = "${" + key + "}";
			sourceUrlParams = sourceUrlParams.replace(var, extraVar.get(key).toString());
		}
		return URLEncoder.createDefault().encode(sourceUrlParams, Charset.defaultCharset());

	}

	/**
	 * 处理手机号
	 *
	 * @param str   字符串内容
	 * @param phone 手机号
	 * @return
	 */
	private String handlePhone(String str, String phone) {
		if (StringUtil.isBlank(str)) {
			return "";
		}
		str = URLDecoder.decode(str, Charset.defaultCharset());
		return str.replace(Constants.TS.phone, phone);
	}

	/**
	 * 处理Header
	 *
	 * @param header
	 * @param extraVar
	 * @return
	 */
	private String handleHeader(String header, JSONObject extraVar) {
		if (extraVar == null || StringUtil.isBlank(header)) {
			return header;
		}
		JSONObject headers = JSONObject.parseObject(header, Feature.OrderedField);
		Set<String> keys = headers.keySet();
		for (String key : keys) {
			String value = headers.get(key).toString();
			Object var = extraVar.get(value.replace("${", "").replace("}", ""));
			if (var != null) {
				headers.put(key, var);
			}
		}
		return headers.toJSONString();
	}

	/**
	 * 处理Header
	 *
	 * @param body     body内容
	 * @param extraVar 魔法变量
	 * @return
	 */
	private String handleBody(String body, JSONObject extraVar) {
		if (extraVar == null || StringUtil.isBlank(body)) {
			return body;
		}
		JSONObject bodys = JSONObject.parseObject(body, Feature.OrderedField);
		Set<String> keys = bodys.keySet();
		for (String key : keys) {
			String value = bodys.get(key).toString();
			Object var = extraVar.get(value.replace("${", "").replace("}", ""));
			if (var != null) {
				bodys.put(key, var);
			}
		}
		return bodys.toJSONString();
	}

	/**
	 * 访问接口
	 *
	 * @param config    配置
	 * @param url       地址
	 * @param urlParams 地址参数
	 * @param headers   header参数
	 * @param body      body参数
	 * @param phone     手机号
	 * @return
	 */
	private TsReqLogEntity excuteUrl(TsGroupApiConfigEntity config, ReqHttpMethodEnum methodType, ReqContentTypeEnum contentType, Address proxy, String url, String urlParams, String headers, String body, String phone, String finalGroupName) {
		TsReqLogEntity tsReqLogEntity = new TsReqLogEntity();
		String result = "";
		try {
			// header处理
			Map<String, Object> headersMap = Collections.emptyMap();
			headers = handleFunction(headers);
			String headerPhoneStr = handlePhone(headers, phone);
			if (StringUtil.isNotBlank(headers)) {
				headersMap = JSONObject.parseObject(headerPhoneStr, Feature.OrderedField).toJavaObject(Map.class);
			}
			// urlParams处理
			tsReqLogEntity.setTheUrl(url);
			if (StringUtil.isNotBlank(urlParams)) {
				urlParams = handlePhone(urlParams, phone);
				urlParams = handleFunction(urlParams);
				url = url + "?" + URLEncoder.createDefault().encode(urlParams, Charset.defaultCharset());
			}
			// body处理
			if (StringUtil.isNotBlank(body)) {
				body = handlePhone(body, phone);
				body = handleFunction(body);
			} else {
				body = "";
			}

			// 延迟请求
			if (config.getIntervalTime() != 0) {
				ThreadUtil.sleep(config.getIntervalTime());
			}

			int timeOut = config.getTimeOut().intValue();
			tsReqLogEntity.setUrlParam(urlParams);
			tsReqLogEntity.setBodyParam(body);
			tsReqLogEntity.setHeaderParam(headerPhoneStr);
			tsReqLogEntity.setConfigId(config.getId());
			tsReqLogEntity.setConfigName(config.getConfigName());
			tsReqLogEntity.setGroupName(finalGroupName);
			tsReqLogEntity.setGroupData(phone);
			tsReqLogEntity.setCreSb(config.getCreSb());
			tsReqLogEntity.setStartTime(new Date());
			tsReqLogEntity.setMatchPattern(config.getMatchPattern());

			HttpRequest httpUtil = HttpRequest.create();
			httpUtil.url(url);
			httpUtil.method(methodType.getKey());
			httpUtil.followRedirect(true);
			httpUtil.validateTLSCertificates(false);
			if (proxy != null) {
				log.info("代理访问: {}", proxy);
				httpUtil.proxy(proxy.getHost(), proxy.getPort());
				httpUtil.proxyBasic(proxy.getUsername(), proxy.getPassword());
			}

			if (contentType != ReqContentTypeEnum.NONE) {
				httpUtil.contentType(contentType.getValue());
			}

			if (timeOut != 0) {
				httpUtil.connectTimeout(timeOut);
			}

			if (!headersMap.isEmpty()) {
				Set<String> keys = headersMap.keySet();
				for (String key : keys) {
					Object haaderValue = headersMap.get(key);
					if ("Cookie".equals(key)) {
						if (haaderValue != null) {
							String cookiesValues = String.valueOf(haaderValue);
							String[] cookiesValueArray = cookiesValues.split(";");
							for (String cookies : cookiesValueArray) {
								String[] cookiesSub = cookies.split("=");
								httpUtil.cookie(cookiesSub[0], cookiesSub[1]);
							}

						}
					} else {
						if (haaderValue != null) {
							httpUtil.header(key, String.valueOf(haaderValue));
						}
					}
				}
			}

			if (StringUtil.isNotBlank(body)) {
				if (contentType == ReqContentTypeEnum.FORM_DATA || contentType == ReqContentTypeEnum.JSON) {
					httpUtil.data(JSONObject.parseObject(body, Feature.OrderedField));
				} else if (contentType == ReqContentTypeEnum.FORM) {
					JSONObject jsonObject = JSONObject.parseObject(body, Feature.OrderedField);
					jsonObject.forEach((key, value) -> {
						httpUtil.data(key, value);
					});
				} else {
					httpUtil.data(body);
				}
			}
			HttpResponse executeResult = httpUtil.execute();
			result = executeResult.getHtml();
			tsReqLogEntity.setRspResult(RspResultEnum.SUCCESSFUL.getKey());
			// 判断是否要保存部分请求结果
			String storeVar = config.getStoreVar();
			if (StringUtil.isNotBlank(storeVar)) {
				try {
					JSONObject jsonResult = JSONObject.parseObject(result, Feature.OrderedField);
					JSONObject rules = JSONObject.parseObject(storeVar, Feature.OrderedField);
					Set<String> ruleKeys = rules.keySet();
					for (String ruleKey : ruleKeys) {
						String rule = rules.getString(ruleKey);
						Object eval = JSONPath.eval(jsonResult, rule);
						rules.put(ruleKey, String.valueOf(eval));
					}
					tsReqLogEntity.setStoreVal(rules.toJSONString());
				} catch (Exception e) {
					e.printStackTrace();
					tsReqLogEntity.setStoreVal("结果非Json数据，不能解析存储");
				}
			}

			// 判断是否匹配上
			MatchTypeEnum matchType = (MatchTypeEnum) BaseEnum.valueOfEnum(MatchTypeEnum.class, config.getMatchType());
			String matchPattern = config.getMatchPattern();
			switch (matchType) {
				case FULL_TEXT:
					if (result.contains(matchPattern)) {
						tsReqLogEntity.setMatchPattern(FlagEnum.YES.getKey());
					} else {
						tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
					}
					break;
				case REGXP:
					if (result.matches(matchPattern)) {
						tsReqLogEntity.setMatchPattern(FlagEnum.YES.getKey());
					} else {
						tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
					}
					break;
				case JSON_PATH:
					boolean valid = JSONObject.isValid(result);
					if (!valid) {
						tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
					}
					String[] split = matchPattern.split(":");
					String exp = split[0];
					String value = split[1];
					Object eval = JSONPath.eval(result, exp);
					if (eval == null) {
						tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
					}
					if (value.equals(String.valueOf(eval))) {
						tsReqLogEntity.setMatchPattern(FlagEnum.YES.getKey());
					} else {
						tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
					}
					break;
			}
			// 如果不需要保留 则不保留接口返回结果
			if (config.getIsRetainResults().equals(SysYesOrNoEnum.YES.getKey())) {
				tsReqLogEntity.setRspBody(result);
			}
		} catch (Exception e) {
			e.printStackTrace();
			result = e.getMessage();
			tsReqLogEntity.setRspResult(RspResultEnum.FAIL.getKey());
			tsReqLogEntity.setMatchPattern(FlagEnum.NO.getKey());
			tsReqLogEntity.setRspBody(result);
		} finally {
			log.info(" 请求接口为{}：{}", methodType.getValue(), url);
			log.info(" header ：{}", headers);
			log.info(" body ：{}", body);
			log.info(" result ：{}", result);
			tsReqLogEntity.setEndTime(new Date());
			tsReqLogEntity.setReqTime(tsReqLogEntity.getEndTime().getTime() - tsReqLogEntity.getStartTime().getTime());
		}
		return tsReqLogEntity;
	}

	@Override
	public void pause(Long id) {
		TsGroupApiConfigEntity tsGroupApiConfigEntity = new TsGroupApiConfigEntity();
		tsGroupApiConfigEntity.setId(id);
		tsGroupApiConfigEntity.setReqStatus(ReqStatusEnum.PAUSE.getKey());
		this.updateById(tsGroupApiConfigEntity);
		taskStatusManageService.getCondition(id);
	}

	@Override
	public void continueExcute(Long id) {
		TsGroupApiConfigEntity tsGroupApiConfigEntity = this.selectById(id);
		if (!Constants.TS.PROXY_NONE.equals(tsGroupApiConfigEntity.getProxyHost())) {
			String proxyHost = sysDictDataService.selectDictLabel(ProxyHostEnum.class.getSimpleName(), tsGroupApiConfigEntity.getProxyHost());
			checkProxy(new Address(proxyHost));
		}
		tsGroupApiConfigEntity.setId(id);
		tsGroupApiConfigEntity.setReqStatus(ReqStatusEnum.REQUESTING.getKey());
		this.updateById(tsGroupApiConfigEntity);

		taskStatusManageService.signalAll(id);
	}

	@Override
	public void stop(Long id) {
		try {
			taskStatusManageService.lock(id);

			// 先终结执行器
			ExecutorService executorService = executors.get(id);
			if (executorService != null) {
				executorService.shutdownNow();
				executorService.shutdown();
				executors.remove(id);
			}

			// 再终结主线程
			Thread thread = theaders.get(id);
			if (thread != null) {
				thread.interrupt();
				theaders.remove(id);
			}

			TsGroupApiConfigEntity old = this.selectById(id);
			TsGroupApiConfigEntity tsGroupApiConfigEntity = new TsGroupApiConfigEntity();
			tsGroupApiConfigEntity.setId(id);
			tsGroupApiConfigEntity.setPageNum(0L);
			tsGroupApiConfigEntity.setStopNum(old.getStopNum() + 1L);
			tsGroupApiConfigEntity.setReqStatus(ReqStatusEnum.HAS_NOT_STARTED.getKey());
			this.updateById(tsGroupApiConfigEntity);
		} finally {
			taskStatusManageService.unlock(id);
			taskStatusManageService.removeAll(id);
		}
	}

	@Override
	public String selectNameById(Long id) {
		return this.selectField(TsGroupApiConfigEntity::getConfigName, SelectWhere().andEqualTo(TsGroupApiConfigEntity::getId, id).end());
	}

	/**
	 * 函数处理
	 *
	 * @return
	 */
	private String handleFunction(String content) {
		if (StringUtil.isBlank(content)) {
			return content;
		}
		for (FunctionExecutor functionExecutor : functionExecutors) {
			content = functionExecutor.handleFunction(content);
		}
		return content;
	}
}
